﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.VisualBasic;
using Microsoft.VisualBasic.CompilerServices;

namespace zykControl
{
    public partial class zykChart
    {
        public zykChart()
        {
            InitializeComponent();
        }
        /// <summary>
        /// 当选中行改变时发生
        /// </summary>
        /// <remarks></remarks>
        public event RowIndexChangedEventHandler RowIndexChanged;

        public delegate void RowIndexChangedEventHandler();
        /// <summary>
        /// 列数量改变时发生
        /// </summary>
        /// <remarks></remarks>
        public event ColumnCountChangedEventHandler ColumnCountChanged;

        public delegate void ColumnCountChangedEventHandler();
        /// <summary>
        /// 行数量改变时发生
        /// </summary>
        /// <remarks></remarks>
        public event RowCountChangedEventHandler RowCountChanged;

        public delegate void RowCountChangedEventHandler();
        ///// <summary>
        ///// 当列标题改变时发生
        ///// </summary>
        ///// <remarks></remarks>
        //public event ColumnCaptionChangedEventHandler ColumnCaptionChanged;

        //public delegate void ColumnCaptionChangedEventHandler(int theIndex);

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            int dWidth = Width - 50;
            int dHeight = Height - 50;
            if (dWidth < 0 || dHeight < 0)
                return;
            e.Graphics.Clear(Color.White);
            double dUnit = Unit;
            double dLength = dUnit * 10d;
            int dColumnCount = ColumnCount;


            // 画标尺线的横线及脚注
            for (int xx = 0; xx <= 10; xx++)
            {
                int dTop = DataToPoint((float)(dUnit * xx), (float)dLength, dHeight);
                e.Graphics.DrawLine(Pens.Black, 0, dTop, 5, dTop);
                e.Graphics.DrawLine(Pens.YellowGreen, 50f, dTop, dWidth + 50 - (float)(dWidth / (double)dColumnCount), dTop);
                e.Graphics.DrawString((dUnit * xx).ToString("g"), Font, Brushes.Black, 6f, dTop);
            }

            if (dWidth < 50)
                return;
            // 画标尺线的竖线
            var dFont = new Font(Font, FontStyle.Bold);
            for (int xx = 0, loopTo = dColumnCount - 1; xx <= loopTo; xx++)
            {
                e.Graphics.DrawLine(Pens.Yellow, (float)(dWidth / (double)dColumnCount * xx) + 50f, 0f, (float)(dWidth / (double)dColumnCount * xx) + 50f, dHeight);
                e.Graphics.DrawString(mColumns[xx], dFont, Brushes.Black, (float)(dWidth / (double)dColumnCount * xx) + 45f, dHeight + 36);
            }

            if (dColumnCount == 0 || dWidth < 50)
                return;

            // 画数据线
            if (dLength == 0d)
                return;
            int dIndex = RowIndex;
            for (int xx = 0, loopTo1 = RowCount - 1; xx <= loopTo1; xx++)
            {
                if (xx == dIndex)
                    continue;
                for (int yy = 1, loopTo2 = dColumnCount - 1; yy <= loopTo2; yy++)
                {
                    int dTop0 = DataToPoint((float)this[xx][yy - 1], (float)dLength, dHeight);
                    int dTop1 = DataToPoint((float)this[xx][yy], (float)dLength, dHeight);
                    e.Graphics.DrawLine(new Pen(mRows[xx].Color, 1f), (float)(dWidth / (double)dColumnCount * (yy - 1)) + 50f, dTop0, (float)(dWidth / (double)dColumnCount * yy) + 50f, dTop1);
                }
            }

            // 画粗线(当前选中线)
            if (dIndex == -1)
                return;
            for (int xx = 1, loopTo3 = dColumnCount - 1; xx <= loopTo3; xx++)
            {
                int dTop0 = DataToPoint((float)this[dIndex][xx - 1], (float)dLength, dHeight);
                int dTop1 = DataToPoint((float)this[dIndex][xx], (float)dLength, dHeight);
                e.Graphics.DrawLine(new Pen(this[dIndex].Color, 3f), (float)(dWidth / (double)dColumnCount * (xx - 1)) + 50f, dTop0, (float)(dWidth / (double)dColumnCount * xx) + 50f, dTop1);
            }

            for (int xx = 0, loopTo4 = dColumnCount - 1; xx <= loopTo4; xx++)
                e.Graphics.DrawString(this[dIndex][xx].ToString("0.00"), Font, Brushes.Black, (float)(dWidth / (double)dColumnCount * xx) + 35f, Conversions.ToSingle(Interaction.IIf(xx / 2 * 2 == xx, dHeight + 16, dHeight + 5)));
        }

        /// <summary>
        /// 从一个数值返回应该显示于界面的高度
        /// </summary>
        /// <returns></returns>
        /// <remarks></remarks>
        private int DataToPoint(float theDate, float theLength, int theHeight)
        {
            return Height - (int)Math.Round(theHeight * theDate / theLength) - 50;
        }

        //private void ZykChart_ColumnCaptionChanged(int theIndex)
        //{
        //    Refresh();
        //}

        private void ZykChart_Resize(object sender, EventArgs e)
        {
            Refresh();
        }

        private void 刷新ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Refresh();
        }

        public override void Refresh()
        {
            base.Refresh();
            变更选择ToolStripMenuItem.DropDownItems.Clear();
            for (int xx = 0, loopTo = mRows.Count - 1; xx <= loopTo; xx++)
            {
                var dPopup = 变更选择ToolStripMenuItem.DropDownItems.Add((xx + 1).ToString() + ": " + mRows[xx].Caption);
                dPopup.Tag = xx;
                dPopup.Font = new Font(Font, FontStyle.Bold);
                dPopup.ForeColor = this[xx].Color;
                dPopup.Click += SelectIndexEvent;
            }
        }

        private void SelectIndexEvent(object sender, EventArgs e)
        {
            ToolStripItem dPopup = (ToolStripMenuItem)sender;
            int dIndex = Conversions.ToInteger(dPopup.Tag);
            RowIndex = dIndex;
            Refresh();
        }

        private void 黑色ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (RowIndex == -1)
                return;
            this[RowIndex].Color = Color.Black;
            Refresh();
        }

        private void 红色ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (RowIndex == -1)
                return;
            this[RowIndex].Color = Color.Red;
            Refresh();
        }

        private void 绿色ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (RowIndex == -1)
                return;
            this[RowIndex].Color = Color.Green;
            Refresh();
        }

        private void 蓝色ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (RowIndex == -1)
                return;
            this[RowIndex].Color = Color.Blue;
            Refresh();
        }

        private void 黄色ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (RowIndex == -1)
                return;
            this[RowIndex].Color = Color.Yellow;
            Refresh();
        }

        private void 青色ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (RowIndex == -1)
                return;
            this[RowIndex].Color = Color.Cyan;
            Refresh();
        }

        private void 紫色ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (RowIndex == -1)
                return;
            this[RowIndex].Color = Color.Purple;
            Refresh();
        }

        private void Form_RowIndexChanged()
        {
            ComboBox1.SelectedIndex = RowIndex;
            Refresh();
        }

        private void Form_RowCountChanged()
        {
            ComboBox1.Items.Clear();
            for (int xx = 0, loopTo = mRows.Count - 1; xx <= loopTo; xx++)
                ComboBox1.Items.Add(mRows[xx].Caption);
            Refresh();
        }

        /// <summary>
        /// 是否显示下拉列表框
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks></remarks>
        public bool ComboVisible
        {
            get
            {
                return ComboBox1.Visible;
            }

            set
            {
                ComboBox1.Visible = value;
            }
        }

        private void ComboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (Created == false)
                return;
            if (ComboBox1.Focused == false)
                return;
            RowIndex = ComboBox1.SelectedIndex;
        }

        private readonly List<string> mColumns = new List<string>();

        /// <summary>
        /// 返回/设置 每行的数据项的数量,设置数量时会清空所有的数据
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks></remarks>
        public int ColumnCount
        {
            get
            {
                return mColumns.Count;
            }

            set
            {
                if (value == mColumns.Count)
                    return;
                mColumns.Clear();
                for (int xx = 0, loopTo = value - 1; xx <= loopTo; xx++)
                    mColumns.Add("C" + (xx + 1).ToString());
                for (int xx = 0, loopTo1 = mRows.Count - 1; xx <= loopTo1; xx++)
                    mRows[xx].SetCount(value);
                ColumnCountChanged?.Invoke();
            }
        }

        /// <summary>
        /// 返回/设置指定列的标题
        /// </summary>
        /// <param name="Index"></param>
        /// <value></value>
        /// <returns></returns>
        /// <remarks></remarks>
        public string Get_Column(int Index)
        {
            return mColumns[Index];
        }

        public void Set_Column(int Index, string value)
        {
            mColumns[Index] = value;
        }

        public int ColumnIndexOf(string theCaption)
        {
            for (int xx = 0, loopTo = mColumns.Count - 1; xx <= loopTo; xx++)
            {
                if ((mColumns[xx].ToLower() ?? "") == (theCaption.ToLower() ?? ""))
                    return xx;
            }

            return -1;
        }

        /// <summary>
        /// 添加一个数据列,此操作会为每一行添加一个数据项
        /// </summary>
        /// <remarks></remarks>
        public void ColumnAdd()
        {
            mColumns.Add("C" + (mColumns.Count + 1).ToString());
            for (int xx = 0, loopTo = mRows.Count - 1; xx <= loopTo; xx++)
                mRows[xx].Add();
            ColumnCountChanged?.Invoke();
        }

        /// <summary>
        /// 添加一个数据列,此操作会为每一行添加一个数据项
        /// </summary>
        /// <param name="theColumnCaption"></param>
        /// <remarks></remarks>
        public void ColumnAdd(string theColumnCaption)
        {
            mColumns.Add(theColumnCaption);
            for (int xx = 0, loopTo = mRows.Count - 1; xx <= loopTo; xx++)
                mRows[xx].Add();
            ColumnCountChanged?.Invoke();
        }

        /// <summary>
        /// 清除所有列,此操作也会清空每行的数据
        /// </summary>
        /// <remarks></remarks>
        public void ClearColumns()
        {
            mColumns.Clear();
            for (int xx = 0, loopTo = mRows.Count - 1; xx <= loopTo; xx++)
                mRows[xx].Clear();
            ColumnCountChanged?.Invoke();
        }

        private readonly List<ZykChartRow> mRows = new List<ZykChartRow>();

        /// <summary>
        /// 返回/设置 行的数量,设置数量时会清空所有数据
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks></remarks>
        public int RowCount
        {
            get
            {
                return mRows.Count;
            }

            set
            {
                if (value == mRows.Count)
                    return;
                mRows.Clear();
                for (int xx = 0, loopTo = value - 1; xx <= loopTo; xx++)
                {
                    var dItem = new ZykChartRow() { Caption = "R" + (mRows.Count + 1).ToString() };
                    dItem.SetCount(ColumnCount);
                    mRows.Add(dItem);
                }

                RowCountChanged?.Invoke();
            }
        }

        /// <summary>
        /// 返回指定行的数据
        /// </summary>
        /// <param name="Index"></param>
        /// <value></value>
        /// <returns></returns>
        /// <remarks></remarks>
        public ZykChartRow this[int Index]
        {
            get
            {
                return mRows[Index];
            }
        }

        public int RowIndexOf(string theCaption)
        {
            for (int xx = 0, loopTo = mRows.Count - 1; xx <= loopTo; xx++)
            {
                if ((mRows[xx].Caption.ToLower() ?? "") == (theCaption.ToLower() ?? ""))
                    return xx;
            }

            return -1;
        }

        /// <summary>
        /// 清除所有数据,包括列和行
        /// </summary>
        /// <remarks></remarks>
        public void Clear()
        {
            mRows.Clear();
            mColumns.Clear();
            ColumnCountChanged?.Invoke();
            RowCountChanged?.Invoke();
            if (mRowIndex != RowIndex)
                RowIndexChanged?.Invoke();
        }

        /// <summary>
        /// 清除所有行数据
        /// </summary>
        /// <remarks></remarks>
        public void ClearRows()
        {
            mRows.Clear();
            RowCountChanged?.Invoke();
        }

        public ZykChartRow RowAdd()
        {
            var dItem = new ZykChartRow() { Caption = "R" + mRows.Count.ToString() };
            dItem.SetCount(ColumnCount);
            mRows.Add(dItem);
            RowCountChanged?.Invoke();
            return dItem;
        }

        public ZykChartRow RowAdd(string theCaption)
        {
            var dItem = new ZykChartRow() { Caption = theCaption };
            dItem.SetCount(ColumnCount);
            mRows.Add(dItem);
            RowCountChanged?.Invoke();
            return dItem;
        }

        public ZykChartRow RowAdd(string theCaption, Color theColor)
        {
            var dItem = new ZykChartRow()
            {
                Caption = theCaption,
                Color = theColor
            };
            dItem.SetCount(ColumnCount);
            mRows.Add(dItem);
            RowCountChanged?.Invoke();
            return dItem;
        }

        /// <summary>
        /// 查找指定标题的行,如果没有找到返回空引用
        /// </summary>
        /// <param name="theCaption"></param>
        /// <returns></returns>
        /// <remarks></remarks>
        public ZykChartRow FindRow(string theCaption)
        {
            for (int xx = 0, loopTo = mRows.Count - 1; xx <= loopTo; xx++)
            {
                if ((mRows[xx].Caption.ToLower() ?? "") == (theCaption.ToLower() ?? ""))
                    return mRows[xx];
            }

            return null;
        }

        private int mRowIndex = -1;
        /// <summary>
        /// 返回/设置 当前选中行的索引
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks></remarks>
        public int RowIndex
        {
            get
            {
                if (mRowIndex >= mRows.Count)
                    mRowIndex = mRows.Count - 1;
                return mRowIndex;
            }

            set
            {
                if (value > mRows.Count - 1)
                    value = mRows.Count - 1;
                if (value < -1)
                    value = -1;
                bool dChange = mRowIndex != value;
                mRowIndex = value;
                if (dChange == true)
                    RowIndexChanged?.Invoke();
            }
        }

        public ZykChartRow SelectedRow
        {
            get
            {
                int dIndex = RowIndex;
                if (dIndex == -1)
                    return null;
                return mRows[dIndex];
            }

            set
            {
                for (int xx = 0, loopTo = mRows.Count - 1; xx <= loopTo; xx++)
                {
                    if (ReferenceEquals(mRows[xx], value))
                    {
                        RowIndex = xx;
                        return;
                    }
                }
            }
        }

        /// <summary>
        /// 返回数据当中的最大值
        /// </summary>
        /// <returns></returns>
        /// <remarks></remarks>
        public double MaxValue()
        {
            if (mRows.Count == 0)
                return 0d;
            double dValue = double.MinValue;
            for (int xx = 0, loopTo = mRows.Count - 1; xx <= loopTo; xx++)
            {
                double dRowValue = mRows[xx].MaxValue();
                if (dRowValue > dValue)
                    dValue = dRowValue;
            }

            return dValue;
        }

        /// <summary>
        /// 返回数据当中的最小值
        /// </summary>
        /// <returns></returns>
        /// <remarks></remarks>
        public double MinValue()
        {
            if (mRows.Count == 0)
                return 0d;
            double dValue = double.MaxValue;
            for (int xx = 0, loopTo = mRows.Count - 1; xx <= loopTo; xx++)
            {
                double dRowValue = mRows[xx].MinValue();
                if (dRowValue < dValue)
                    dValue = dRowValue;
            }

            return dValue;
        }

        /// <summary>
        /// 返回最大最小数之差,如果为0则返回1
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks></remarks>
        public double Length
        {
            get
            {
                double dLength = MaxValue() - MinValue();
                if (dLength == 0d)
                    dLength = 1d;
                return dLength;
            }
        }

        /// <summary>
        /// 返回两位有效数字,这个数字大约是最大最小数之差的十分之一,但不会比差值小
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks></remarks>
        public double Unit
        {
            get
            {
                double dLen = Length / 10d;
                int dPos = TenPos(dLen);
                double dLenR = dLen / Math.Pow(10d, dPos);
                int dLenI = (int)Math.Round(Math.Ceiling(dLenR));
                return dLenI * Math.Pow(10d, dPos);
            }
        }

        /// <summary>
        /// 返回某数字为10的倍数
        /// </summary>
        /// <param name="theValue"></param>
        /// <returns></returns>
        /// <remarks></remarks>
        public int TenPos(double theValue)
        {
            theValue = Math.Abs(theValue);
            int dPos = 0;
            if (theValue == 0d)
                return 0;
            while (theValue < 1d)
            {
                theValue *= 10d;
                dPos -= 1;
            }

            while (theValue >= 10d)
            {
                theValue /= 10d;
                dPos += 1;
            }

            return dPos;
        }

        private void ZykChart_ColumnCountChanged()
        {
            Refresh();
        }

        /// <summary>
        /// 向指定行指定列添加一个数据,成功时返回True
        /// </summary>
        /// <param name="RowCaption"></param>
        /// <param name="ColumnCaption"></param>
        /// <param name="theData"></param>
        /// <param name="IsCreateRow"></param>
        /// <param name="IsCreateColumn"></param>
        /// <returns></returns>
        /// <remarks></remarks>
        public bool AddItemData(string RowCaption, string ColumnCaption, double theData, bool IsCreateRow = true, bool IsCreateColumn = false)
        {
            int dRowIndex = RowIndexOf(RowCaption);
            ZykChartRow dRow;
            if (dRowIndex == -1)
            {
                if (IsCreateRow == false)
                    return false;
                dRow = RowAdd(RowCaption);
            }
            else
            {
                dRow = this[dRowIndex];
            }

            int dColIndex = ColumnIndexOf(ColumnCaption);
            if (dColIndex == -1)
            {
                if (IsCreateColumn == false)
                    return false;
                ColumnAdd(ColumnCaption);
                dRow[ColumnCount - 1] = theData;
            }
            else
            {
                dRow[dColIndex] = theData;
            }

            return true;
        }
    }

    /// <summary>
    /// 表示zykChart的一行数据
    /// </summary>
    /// <remarks></remarks>
    public class ZykChartRow
    {
        /// <summary>
        /// 表示此行数据的颜色
        /// </summary>
        /// <remarks></remarks>
        public Color Color = Color.FromArgb((int)Math.Round(VBMath.Rnd() * 255f), (int)Math.Round(VBMath.Rnd() * 255f), (int)Math.Round(VBMath.Rnd() * 255f));
        /// <summary>
        /// 表示此行的标题
        /// </summary>
        /// <remarks></remarks>
        public string Caption = "";
        private readonly List<double> mItems = new List<double>();

        public int Count
        {
            get
            {
                return mItems.Count;
            }
        }

        public double this[int Index]
        {
            get
            {
                return mItems[Index];
            }

            set
            {
                mItems[Index] = value;
            }
        }

        public void Clear()
        {
            mItems.Clear();
        }

        /// <summary>
        /// 添加一个数据项,并为其设0值
        /// </summary>
        /// <remarks></remarks>
        internal void Add()
        {
            mItems.Add(0d);
        }

        /// <summary>
        /// 添加一个数据项,并设置初始的值
        /// </summary>
        /// <param name="Value"></param>
        /// <remarks></remarks>
        internal void Add(double Value)
        {
            mItems.Add(Value);
        }

        /// <summary>
        /// 设置此行的数据项的数量
        /// </summary>
        /// <param name="theCount"></param>
        /// <remarks></remarks>
        internal void SetCount(int theCount)
        {
            mItems.Clear();
            for (int xx = 0, loopTo = theCount - 1; xx <= loopTo; xx++)
                Add();
        }

        /// <summary>
        /// 获取本行数据当中的最大值
        /// </summary>
        /// <returns></returns>
        /// <remarks></remarks>
        public double MaxValue()
        {
            if (mItems.Count == 0)
                return 1d;
            double dValue = double.MinValue;
            for (int xx = 0, loopTo = mItems.Count - 1; xx <= loopTo; xx++)
            {
                if (mItems[xx] > dValue)
                    dValue = mItems[xx];
            }

            return dValue;
        }

        /// <summary>
        /// 获取本行数据当中的最小值
        /// </summary>
        /// <returns></returns>
        /// <remarks></remarks>
        public double MinValue()
        {
            if (mItems.Count == 0)
                return 0d;
            double dValue = double.MaxValue;
            for (int xx = 0, loopTo = mItems.Count - 1; xx <= loopTo; xx++)
            {
                if (mItems[xx] < dValue)
                    dValue = mItems[xx];
            }

            return dValue;
        }
    }
}